package net.masker.bbtweet;

import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.StreamConnection;
import net.rim.blackberry.api.mail.Address;
import net.rim.blackberry.api.mail.Folder;
import net.rim.blackberry.api.mail.Message;
import net.rim.blackberry.api.mail.Session;
import net.rim.blackberry.api.mail.Store;
import net.rim.device.api.io.http.HttpProtocolConstants;
import net.rim.device.api.notification.NotificationsManager;
import net.rim.device.api.xml.parsers.*;
import org.w3c.dom.*;

class bbtweetConnectionManager extends Thread
{
	private static bbtweetProperties properties;
    private static String friendsTimelineURL = "http://twitter.com/statuses/friends_timeline.xml";
    
    
	/**
	 * Parses XML stream, returning root element
	 * @param stream
	 * @return
	 */
    private final Element parseXML(InputStream stream)
	{
		
		try
		{
		//Parse input stream, get root element & normalize, returning root element
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(stream);
        
        Element rootElement = document.getDocumentElement();
        rootElement.normalize();
        
        return rootElement;
        
		}
		catch (Exception e)
		{
			System.out.println(e.toString());
			return null;
		}
	}
    
    private final boolean disabled()
    {
    	properties = bbtweetProperties.fetch();
    	if (!properties.isBbtweetEnabled())
    	{
    		properties.setConnectionManagerStarted(false);
    		properties.save();
    		return true;
    	}
    	else
    	{
    		properties.setConnectionManagerStarted(true);
    		properties.save();
    		return false;
    	}
    }
	
	public void run()
    {
		Element root = null;
		
		//Only allow one Connection Manager thread to run at a time
		properties = bbtweetProperties.fetch();
		if (properties.isConnectionManagerStarted())
		{
			return;
		}
		
		for(;;)//ever
        {
			
    		// Check that bbtweet is still enabled at beginning and end of loop
			// This updates all the properties and starts the shutdown process if necessary
			if (disabled())
				return;
            
			// Open stream and poll data
            try
            {
            	int lastID, newID;
				properties = bbtweetProperties.fetch();
				lastID = newID = properties.getLastID();
				// If bbtweet is being initialized, only the last message is retrieved because we
				// just need to update lastID. If not, pull up to 200 messages since the last ID.
				// If the lastID has been reset to 0, just pull the last 20 updates
            	String url = friendsTimelineURL + (lastID == 0 ? "" : ("?count=" + (lastID == -1 ? "1" : ("200" 
            			+ "&since_id=" + lastID))));
            	StreamConnection s = null;
    			s = (StreamConnection)Connector.open(url);
                HttpConnection httpConn = (HttpConnection)s;
                properties = bbtweetProperties.fetch();
                httpConn.setRequestProperty(HttpProtocolConstants.HEADER_AUTHORIZATION,"Basic "
                		+ properties.getAuthenticationHash());

                int status = httpConn.getResponseCode();
                        
                if (status == HttpConnection.HTTP_OK)
                {
                	properties = bbtweetProperties.fetch();
                	properties.setBbtweetStatusMessage("Worked!");
                	properties.save();
                	
                	root = parseXML(httpConn.openInputStream());
                	// clean up connection
                	httpConn = null;
                	s = null;
                	
                	
					if (root != null) 
					{
						NodeList childNodes = root.getElementsByTagName("status");
						// clean up
						root = null;
						int numChildren = childNodes.getLength();
						for (int i = numChildren - 1; i >= 0; --i) 
						{
							String[] Values = new String[18];
							int index = 0;
							for (int j = 0; j < childNodes.item(i).getChildNodes().getLength(); ++j) 
							{
								// skip whitespace
								if (childNodes.item(i).getChildNodes().item(j).getNodeType() != 1)
									continue;
								if ("user".equals(childNodes.item(i).getChildNodes().item(j).getNodeName()))
								{
									NodeList userNodes = childNodes.item(i).getChildNodes().item(j).getChildNodes();
									for (int k = 0; k < userNodes.getLength(); ++k)
									{
										// Skip whitespace
										if (userNodes.item(k).getNodeType() != 1)
											continue;
										try
										{
											Values[index] = userNodes.item(k).getFirstChild().getNodeValue();
										}
										catch (NullPointerException e)
										{
											// null is OK
										}
										index++;
									}
									continue;
								}
								
								try
								{
									Values[index] = childNodes.item(i).getChildNodes().item(j).getFirstChild().getNodeValue();
								}
								catch (NullPointerException e)
								{
									// null is ok
								}
								index++;
								
							}
							
							
							// push out update if new
							int thisID = Integer.parseInt(Values[1]);
							if (thisID > lastID)
							{
								if (thisID > newID)
									newID = thisID;
								
								// discard messages from user and messages on first run
								if ((Values[10].compareTo(properties.getUsername()) == 0) ||
										(lastID == -1))
									continue;
								
								Store store = Session.getDefaultInstance().getStore();
								Folder[] folders = store.list(Folder.INBOX);
								Folder inbox = folders[0];
								Message msg = new Message(inbox);
								try
								{
									// Create message object for incoming twitter message
									Address from = new Address("http://bbtweet.googlecode.com/", "@" + Values[11]);
									msg.setFrom(from);
									msg.setContent(Values[2]);
									msg.setInbound(true);
									// Add message to inbox and set status to received
									inbox.appendMessage(msg);
									msg.setStatus(Message.Status.RX_RECEIVED, 0);
									// Trigger immediate notification
									NotificationsManager.triggerImmediateEvent(bbtweet.NOTIFICATIONS_ID_1, 0, this, null);
									
								}
								catch (Exception e)
								{
									//TODO handle errors
								}
							}
						}
						// Clean up
						childNodes = null;
						
						properties = bbtweetProperties.fetch();
						properties.setBbtweetStatusMessage("Complete");
						properties.setLastID(newID);
						properties.save();
					}
                	
                }
                else
                {
                	properties = bbtweetProperties.fetch();
                	properties.setBbtweetStatusMessage(httpConn.getResponseMessage());
                	properties.save();
                }
            }
            catch (IOException e) 
            {
            	properties = bbtweetProperties.fetch();
            	properties.setBbtweetStatusMessage(e.toString());
            	properties.save();
            }
            
            // Sleep for interval delay
            int sleepTime = properties.getUpdateInterval();
            for (int i = 0; i < sleepTime; ++i)
            {
	            // check if the service has been disabled and shutdown if necessary
            	if (disabled())
            		return;
            	
            	// check that sleep time has not changed
            	// if sleep time has changed, adjust accordingly
            	properties = bbtweetProperties.fetch();
            	int curSleepTime = properties.getUpdateInterval();
            	if (curSleepTime != sleepTime)
            	{
            		int diff = curSleepTime - sleepTime;
            		i = i - diff; // if update interval was increased i will decrease
            		sleepTime = curSleepTime;
            		continue; // re-evaluate for loop 
            	}
            	
            	try
	            {
	            	sleep(60000);
	            }
	            catch (InterruptedException e) 
	            {
	                properties = bbtweetProperties.fetch();
	                properties.setBbtweetStatusMessage(e.toString());
	                properties.save();
	            }
            }
            
        }
    }
    
}